﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
using LotroTweeter.Properties;
using LotroTweeter.Repositories;
using LotroTweeter.Data;

namespace LotroTweeter.Engine
{
    public enum LotroEventType
    {
        NewMember,
        LevelUp
    }

    public class LotroEventArgs : EventArgs
    {
        public LotroEventType EventType { get; set; }
        public KinMember Member { get; set; }
    }

    public delegate void LotroWatcherEventHandler(object sender, IEnumerable<LotroEventArgs> buildWatcherEventArgs);
    public delegate void LotroWatcherInitializingHandler(object sender, EventArgs eventArgs);
    public delegate void LotroWatcherStoppingHandler(object sender, EventArgs eventArgs);
    public delegate void LotroWatcherErrorHandler(object sender, ThreadExceptionEventArgs eventArgs);

    public class LotroWatcher
    {
        public event LotroWatcherInitializingHandler LotroWatcherInitializing;
        public event LotroWatcherEventHandler NewMemberEvent;
        public event LotroWatcherEventHandler LevelUpEvent;
        public event LotroWatcherStoppingHandler LotroWatcherStopping;
        public event LotroWatcherErrorHandler ErrorOccurred;

        private readonly string kinship = Settings.Default.Kinship;
        private readonly LotroConnector connector = new LotroConnector();
        private KinshipRepository kinRepository = new KinshipRepository();

        private Thread workerThread;

        private void Worker()
        {
            while (true)
            {
                try
                {
                    var connector = new LotroConnector();
                    var newRoster = connector.GetKinRoster(kinship);
                    if (newRoster.Descendants("error").Count() == 0)
                    {
                        var oldRoster = kinRepository.Load();
                        //making sure we have some old data
                        if (oldRoster.Descendants("guild").Count() != 0)
                        {
                            var dataComparer = new DataEngine(oldRoster, newRoster);
                            var newMembers = dataComparer.GetNewMembers();
                            var levelUps = dataComparer.GetLevelUps();
                            ProcessNewMembers(newMembers);
                            ProcessLevelUps(levelUps);
                        }
                        kinRepository.Save(newRoster);
                    }
                }
                catch (ThreadAbortException)
                {
                    return;
                }
                catch (Exception e)
                {
                    if (ErrorOccurred != null)
                    {
                        var args = new ThreadExceptionEventArgs(e);
                        ErrorOccurred(this, args);
                    }
                }

                //Sleep for a number of hours
                Thread.Sleep(new TimeSpan(Settings.Default.PollPeriod, 0, 0));
            }
        }

        private void ProcessNewMembers(IEnumerable<KinMember> newMembers)
        {
            if (NewMemberEvent == null || newMembers.Count() == 0)
            {
                return;
            }
            var args = (from m in newMembers
                        select new LotroEventArgs()
                        {
                            EventType = LotroEventType.NewMember,
                            Member = m
                        }).ToList();
            NewMemberEvent(this, args);
        }

        private void ProcessLevelUps(IEnumerable<KinMember> levelUps)
        {
            if (LevelUpEvent == null || levelUps.Count() == 0)
            {
                return;
            }
            var args = (from m in levelUps
                        //where m.Level >= 55 || m.Level % 10 == 0
                        select new LotroEventArgs()
                        {
                            EventType = LotroEventType.LevelUp,
                            Member = m
                        }).ToList();
            LevelUpEvent(this, args);
        }

        public void Start()
        {
            if (workerThread != null)
            {
                throw new Exception("The worker thread has already been started.");
            }

            if (LotroWatcherInitializing != null)
                LotroWatcherInitializing(this, new EventArgs());

            workerThread = new Thread(Worker);
            workerThread.IsBackground = true;
            workerThread.Start();

        }

        public void Stop()
        {
            if (workerThread == null)
            {
                throw new Exception("The worker thread was not started.");
            }

            if (LotroWatcherStopping != null)
                LotroWatcherStopping(this, new EventArgs());

            workerThread.Abort();
            workerThread = null;
        }
    }
}
